//! 指标导出模块
//! 
//! 提供Prometheus等格式的指标导出功能

use async_trait::async_trait;
use axum::{
    extract::State,
    http::StatusCode,
    response::{IntoResponse, Response},
    routing::get,
    Router,
};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use anyhow::Result;
use tracing::{debug, info, error};

use crate::{PrometheusConfig, MetricsCollector, MetricData, MetricType, MetricValue};

/// 指标导出器trait
#[async_trait]
pub trait MetricsExporter: Send + Sync {
    /// 导出指标
    async fn export_metrics(&self, metrics: &[MetricData]) -> Result<String>;
    
    /// 获取导出器名称
    fn name(&self) -> &str;
    
    /// 获取内容类型
    fn content_type(&self) -> &str;
}

/// Prometheus导出器
pub struct PrometheusExporter {
    /// 配置
    config: PrometheusConfig,
    /// 指标收集器
    metrics_collector: Option<Arc<MetricsCollector>>,
    /// 服务器句柄
    server_handle: Arc<RwLock<Option<tokio::task::JoinHandle<()>>>>,
}

impl PrometheusExporter {
    /// 创建新的Prometheus导出器
    pub async fn new(config: PrometheusConfig) -> Result<Self> {
        Ok(Self {
            config,
            metrics_collector: None,
            server_handle: Arc::new(RwLock::new(None)),
        })
    }

    /// 设置指标收集器
    pub fn with_metrics_collector(mut self, collector: Arc<MetricsCollector>) -> Self {
        self.metrics_collector = Some(collector);
        self
    }

    /// 启动HTTP服务器
    pub async fn start(&self) -> Result<()> {
        if !self.config.enabled {
            info!("Prometheus导出器已禁用");
            return Ok(());
        }

        let collector = self.metrics_collector.clone();
        let metrics_path = self.config.metrics_path.clone();
        let listen_addr = format!("{}:{}", self.config.listen_address, self.config.port);

        // 创建路由
        let app = Router::new()
            .route(&metrics_path, get(metrics_handler))
            .route("/health", get(health_handler))
            .with_state(AppState { collector });

        info!("启动Prometheus导出器，监听地址: {}", listen_addr);

        // 启动服务器
        let listener = tokio::net::TcpListener::bind(&listen_addr).await?;
        let server_handle = tokio::spawn(async move {
            if let Err(e) = axum::serve(listener, app).await {
                error!("Prometheus导出器服务器错误: {}", e);
            }
        });

        *self.server_handle.write().await = Some(server_handle);
        info!("Prometheus导出器启动成功");
        Ok(())
    }

    /// 停止HTTP服务器
    pub async fn stop(&self) -> Result<()> {
        let mut handle = self.server_handle.write().await;
        if let Some(server_handle) = handle.take() {
            server_handle.abort();
            info!("Prometheus导出器已停止");
        }
        Ok(())
    }

    /// 格式化指标为Prometheus格式
    fn format_metric(&self, metric: &MetricData) -> String {
        let mut output = String::new();

        // 添加帮助信息
        if let Some(help) = &metric.help {
            output.push_str(&format!("# HELP {} {}\n", metric.name, help));
        }

        // 添加类型信息
        let prometheus_type = match metric.metric_type {
            MetricType::Counter => "counter",
            MetricType::Gauge => "gauge",
            MetricType::Histogram => "histogram",
            MetricType::Summary => "summary",
        };
        output.push_str(&format!("# TYPE {} {}\n", metric.name, prometheus_type));

        // 格式化标签
        let labels = if metric.labels.is_empty() {
            String::new()
        } else {
            let label_pairs: Vec<String> = metric.labels
                .iter()
                .map(|(k, v)| format!("{}=\"{}\"", k, v))
                .collect();
            format!("{{{}}}", label_pairs.join(","))
        };

        // 格式化值
        match &metric.value {
            MetricValue::Integer(value) => {
                output.push_str(&format!("{}{} {} {}\n", 
                    metric.name, labels, value, metric.timestamp * 1000));
            }
            MetricValue::Float(value) => {
                output.push_str(&format!("{}{} {} {}\n", 
                    metric.name, labels, value, metric.timestamp * 1000));
            }
            MetricValue::Histogram { buckets, sum, count } => {
                // 输出直方图桶
                for (upper_bound, bucket_count) in buckets {
                    let bucket_labels = if metric.labels.is_empty() {
                        format!("{{le=\"{}\"}}", upper_bound)
                    } else {
                        let mut all_labels = metric.labels.clone();
                        all_labels.insert("le".to_string(), upper_bound.to_string());
                        let label_pairs: Vec<String> = all_labels
                            .iter()
                            .map(|(k, v)| format!("{}=\"{}\"", k, v))
                            .collect();
                        format!("{{{}}}", label_pairs.join(","))
                    };
                    output.push_str(&format!("{}_bucket{} {} {}\n", 
                        metric.name, bucket_labels, bucket_count, metric.timestamp * 1000));
                }
                
                // 输出总和
                output.push_str(&format!("{}_sum{} {} {}\n", 
                    metric.name, labels, sum, metric.timestamp * 1000));
                
                // 输出计数
                output.push_str(&format!("{}_count{} {} {}\n", 
                    metric.name, labels, count, metric.timestamp * 1000));
            }
            MetricValue::Summary { quantiles, sum, count } => {
                // 输出分位数
                for (quantile, value) in quantiles {
                    let quantile_labels = if metric.labels.is_empty() {
                        format!("{{quantile=\"{}\"}}", quantile)
                    } else {
                        let mut all_labels = metric.labels.clone();
                        all_labels.insert("quantile".to_string(), quantile.to_string());
                        let label_pairs: Vec<String> = all_labels
                            .iter()
                            .map(|(k, v)| format!("{}=\"{}\"", k, v))
                            .collect();
                        format!("{{{}}}", label_pairs.join(","))
                    };
                    output.push_str(&format!("{}{} {} {}\n", 
                        metric.name, quantile_labels, value, metric.timestamp * 1000));
                }
                
                // 输出总和
                output.push_str(&format!("{}_sum{} {} {}\n", 
                    metric.name, labels, sum, metric.timestamp * 1000));
                
                // 输出计数
                output.push_str(&format!("{}_count{} {} {}\n", 
                    metric.name, labels, count, metric.timestamp * 1000));
            }
        }

        output
    }
}

#[async_trait]
impl MetricsExporter for PrometheusExporter {
    async fn export_metrics(&self, metrics: &[MetricData]) -> Result<String> {
        let mut output = String::new();
        
        // 按指标名称分组
        let mut grouped_metrics: HashMap<String, Vec<&MetricData>> = HashMap::new();
        for metric in metrics {
            grouped_metrics.entry(metric.name.clone()).or_default().push(metric);
        }

        // 格式化每个指标组
        for (_, metric_group) in grouped_metrics {
            for metric in metric_group {
                output.push_str(&self.format_metric(metric));
            }
            output.push('\n');
        }

        debug!("导出了 {} 个指标", metrics.len());
        Ok(output)
    }

    fn name(&self) -> &str {
        "prometheus"
    }

    fn content_type(&self) -> &str {
        "text/plain; version=0.0.4; charset=utf-8"
    }
}

/// 应用状态
#[derive(Clone)]
struct AppState {
    collector: Option<Arc<MetricsCollector>>,
}

/// 指标处理器
async fn metrics_handler(State(state): State<AppState>) -> Response {
    match state.collector {
        Some(collector) => {
            match collector.get_metrics().await {
                Ok(metrics) => {
                    let exporter = PrometheusExporter {
                        config: PrometheusConfig {
                            listen_address: "0.0.0.0".to_string(),
                            port: 9090,
                            metrics_path: "/metrics".to_string(),
                            enabled: true,
                        },
                        metrics_collector: None,
                        server_handle: Arc::new(RwLock::new(None)),
                    };
                    
                    match exporter.export_metrics(&metrics).await {
                        Ok(output) => {
                            (
                                StatusCode::OK,
                                [("content-type", exporter.content_type())],
                                output,
                            ).into_response()
                        }
                        Err(e) => {
                            error!("导出指标失败: {}", e);
                            (StatusCode::INTERNAL_SERVER_ERROR, "导出指标失败").into_response()
                        }
                    }
                }
                Err(e) => {
                    error!("获取指标失败: {}", e);
                    (StatusCode::INTERNAL_SERVER_ERROR, "获取指标失败").into_response()
                }
            }
        }
        None => {
            (StatusCode::SERVICE_UNAVAILABLE, "指标收集器未配置").into_response()
        }
    }
}

/// 健康检查处理器
async fn health_handler() -> Response {
    (StatusCode::OK, "OK").into_response()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::metrics::{MetricsCollector, MetricDefinition};

    #[tokio::test]
    async fn test_prometheus_exporter_creation() {
        let config = PrometheusConfig {
            listen_address: "127.0.0.1".to_string(),
            port: 9091,
            metrics_path: "/metrics".to_string(),
            enabled: true,
        };

        let exporter = PrometheusExporter::new(config).await.unwrap();
        assert_eq!(exporter.name(), "prometheus");
        assert!(exporter.content_type().contains("text/plain"));
    }

    #[tokio::test]
    async fn test_prometheus_format() {
        let config = PrometheusConfig {
            listen_address: "127.0.0.1".to_string(),
            port: 9091,
            metrics_path: "/metrics".to_string(),
            enabled: true,
        };

        let exporter = PrometheusExporter::new(config).await.unwrap();
        
        let mut labels = HashMap::new();
        labels.insert("service".to_string(), "api".to_string());
        
        let metric = MetricData::new(
            "http_requests_total".to_string(),
            MetricType::Counter,
            MetricValue::Integer(42),
            labels,
        ).with_help("Total HTTP requests".to_string());

        let output = exporter.export_metrics(&[metric]).await.unwrap();
        
        assert!(output.contains("# HELP http_requests_total Total HTTP requests"));
        assert!(output.contains("# TYPE http_requests_total counter"));
        assert!(output.contains("http_requests_total{service=\"api\"} 42"));
    }

    #[tokio::test]
    async fn test_histogram_format() {
        let config = PrometheusConfig {
            listen_address: "127.0.0.1".to_string(),
            port: 9091,
            metrics_path: "/metrics".to_string(),
            enabled: true,
        };

        let exporter = PrometheusExporter::new(config).await.unwrap();
        
        let metric = MetricData::new(
            "request_duration".to_string(),
            MetricType::Histogram,
            MetricValue::Histogram {
                buckets: vec![(0.1, 10), (0.5, 25), (1.0, 40)],
                sum: 15.5,
                count: 40,
            },
            HashMap::new(),
        );

        let output = exporter.export_metrics(&[metric]).await.unwrap();
        
        assert!(output.contains("request_duration_bucket{le=\"0.1\"} 10"));
        assert!(output.contains("request_duration_bucket{le=\"0.5\"} 25"));
        assert!(output.contains("request_duration_bucket{le=\"1.0\"} 40"));
        assert!(output.contains("request_duration_sum 15.5"));
        assert!(output.contains("request_duration_count 40"));
    }

    #[tokio::test]
    async fn test_metrics_collector_integration() {
        let collector = Arc::new(MetricsCollector::new());
        
        // 注册指标定义
        let definition = MetricDefinition {
            name: "test_gauge".to_string(),
            metric_type: MetricType::Gauge,
            help: "Test gauge metric".to_string(),
            label_names: vec!["instance".to_string()],
        };
        collector.register_metric(definition).await.unwrap();

        // 记录指标
        let mut labels = HashMap::new();
        labels.insert("instance".to_string(), "server1".to_string());
        collector.record_metric("test_gauge", MetricValue::Float(42.5), labels).await.unwrap();

        // 创建导出器
        let config = PrometheusConfig {
            listen_address: "127.0.0.1".to_string(),
            port: 9092,
            metrics_path: "/metrics".to_string(),
            enabled: true,
        };
        let exporter = PrometheusExporter::new(config).await.unwrap()
            .with_metrics_collector(collector.clone());

        // 导出指标
        let metrics = collector.get_metrics().await.unwrap();
        let output = exporter.export_metrics(&metrics).await.unwrap();
        
        assert!(output.contains("test_gauge{instance=\"server1\"} 42.5"));
    }
}
